/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "Tpm.h"

// This function is called to process a _TPM_Hash_End indication.
/*
This indication from the TPM interface indicates the end of the H-CRTM measurement. This indication is 
discarded and no other action performed if the TPM does not contain an H-CRTM Event Sequence context.
NOTE 1 An H-CRTM Event Sequence context is created by _TPM_Hash_Start().
If the H-CRTM Event Sequence occurs after TPM2_Startup(), the TPM will set all of the PCR designated in 
the platform-specific specifications as resettable by this event to the value indicated in the platform 
specific specification and increment restartCount. The TPM will then Extend the Event Sequence digest/digests 
into the designated D-RTM PCR (PCR[17])
来自 TPM 接口的指示表明 H-CRTM 测量结束。 如果 TPM 不包含 H-CRTM 事件序列上下文，则该指示将被丢弃并且不会执行其他操作。
注 1 H-CRTM 事件序列上下文由 _TPM_Hash_Start() 创建。
如果 H-CRTM 事件序列发生在 TPM2_Startup() 之后，TPM 会将平台特定规范中指定的所有 PCR 设置为可由该事件重置为平台特定规范中指示的值，
并递增 restartCount。 然后 TPM 会将事件序列摘要扩展到指定的 D-RTM PCR (PCR[17])

PCR[17][hashAlg] ≔ HhashAlg (initial_value || HhashAlg (hash_data)) (7)
where
hashAlg hash algorithm associated with a bank of PCR
initial_value initialization value specified in the platform-specific specification (should be 0…0)
hash_data all the octets of data received in _TPM_Hash_Data indications

在哪里
hashAlg 与 PCR 相关联的哈希算法
initial_value 平台特定规范中指定的初始化值（应为 0…0）
hash_data _TPM_Hash_Data 指示中接收到的所有八位字节数据

A _TPM_Hash_End indication that occurs after TPM2_Startup() will increment pcrUpdateCounter unless a platform-specific 
specification excludes modifications of PCR[DRTM] from causing an increment.
A platform-specific specification may allow an H-CRTM Event Sequence before TPM2_Startup(). If so, _TPM_Hash_End will 
complete the digest, initialize PCR[0] with a digest-size value of 4, and then extend the H-CRTM Event Sequence data into PCR[0].
PCR[0][hashAlg] ≔ HhashAlg (0…04 || HhashAlg (hash_data)) (8)
NOTE 2 The entire sequence of _TPM_Hash_Start, _TPM_Hash_Data, and _TPM_Hash_End are required to complete before TPM2_Startup() 
or the sequence will have no effect on the TPM.
NOTE 3 PCR[0] does not need to be updated according to (8) until the end of TPM2_Startup().

在 TPM2_Startup() 之后出现的 _TPM_Hash_End 指示将递增 pcrUpdateCounter，除非特定于平台的规范排除了 PCR[DRTM] 的修改导致递增。
特定于平台的规范可能允许在 TPM2_Startup() 之前使用 H-CRTM 事件序列。 如果是，_TPM_Hash_End 将完成摘要，用摘要大小值 4 初始化 PCR[0]，
然后将 H-CRTM 事件序列数据扩展到 PCR[0]。
PCR[0][hashAlg] ≔ HhashAlg (0…04 || HhashAlg (hash_data)) (8)
注 2 _TPM_Hash_Start、_TPM_Hash_Data 和 _TPM_Hash_End 的整个序列需要在 TPM2_Startup() 之前完成，否则该序列将对 TPM 没有影响。
注 3 直到 TPM2_Startup() 结束之前，PCR[0] 不需要根据 (8) 进行更新。
*/
LIB_EXPORT void
_TPM_Hash_End(
    void
    )
{
    UINT32          i;
    TPM2B_DIGEST    digest;
    HASH_OBJECT    *hashObject;
    TPMI_DH_PCR     pcrHandle;

    // If the DRTM handle is not being used, then either _TPM_Hash_Start has not
    // been called, _TPM_Hash_End was previously called, or some other command
    // was executed and the sequence was aborted.
    if(g_DRTMHandle == TPM_RH_UNASSIGNED)
        return;

    // Get DRTM sequence object
    hashObject = (HASH_OBJECT *)HandleToObject(g_DRTMHandle);

    // Is this _TPM_Hash_End after Startup or before
    if(TPMIsStarted())
    {
        // After

        // Reset the DRTM PCR
        PCRResetDynamics();

        // Extend the DRTM_PCR.
        pcrHandle = PCR_FIRST + DRTM_PCR;

        // DRTM sequence increments restartCount
        gr.restartCount++;
    }
    else
    {
        pcrHandle = PCR_FIRST + HCRTM_PCR;
        g_DrtmPreStartup = TRUE;
    }

    // Complete hash and extend PCR, or if this is an HCRTM, complete
    // the hash, reset the H-CRTM register (PCR[0]) to 0...04, and then
    // extend the H-CRTM data
    for(i = 0; i < HASH_COUNT; i++)
    {
        TPMI_ALG_HASH       hash = CryptHashGetAlgByIndex(i);
        // make sure that the PCR is implemented for this algorithm
        if(PcrIsAllocated(pcrHandle,
                          hashObject->state.hashState[i].hashAlg))
        {
            // Complete hash
            digest.t.size = CryptHashGetDigestSize(hash);
            CryptHashEnd2B(&hashObject->state.hashState[i], &digest.b);

            PcrDrtm(pcrHandle, hash, &digest);
        }
    }

    // Flush sequence object.
    FlushObject(g_DRTMHandle);

    g_DRTMHandle = TPM_RH_UNASSIGNED;


    return;
}